<?php
/**
 * 处理和接收 HTTP 请求的内容
 *
 * @category   ORG
 * @package    ORG
 * @subpackage Request
 * @author     海啸 <459103503@qq.com>
 */
class HttpRequest
{
    const DEFAULT_EXPIRES = 1000;

    private $_server, $_get, $_post, $_files, $_cookie, $_put;

    private $_rawBody;

    /**
     * construction
     *
     * @param array $server $_SERVER
     * @param array $get    $_GET
     * @param array $post   $_GET
     * @param array $files  $_FILES
     * @param array $cookie $_COOKIE
     */
    public function __construct($server = [], $get = [], $post = [], $files = [], $cookie = [])
    {
        $this->_get     = new RequestData($get);
        $this->_post    = new RequestData($post);
        $this->_cookie  = new RequestData($cookie);
        $this->_files   = $files;
        $this->_server  = $server;
    }

    /**
     * get the application name of this request
     *
     * @return string
     */
    public function getRequestApp()
    {
        return isset($this->_server['REQUEST_APPLICATION']) ?
            $this->_server['REQUEST_APPLICATION'] : '';
    }

    /**
     * get filename of current reqeust
     *
     * @return string
     */
    public function getScriptName()
    {
        return $this->_server['SCRIPT_NAME'];
    }

    /**
     * Get the arguments
     *
     * @return RequestData
     */
    public function getArgs()
    {
        return $this->_get;
    }


    /**
     * get the raw body data
     *
     * @return string
     */
    public function getRawBody()
    {
        if (!isset($this->_rawBody)) {
            $this->_rawBody = file_get_contents('php://input');
        }
        return $this->_rawBody;
    }

    /**
     * Get the cookie data
     *
     * @return RequestData
     **/
    public function getCookie()
    {
        return $this->_cookie;
    }

    /**
     * Get the upload files
     *
     * @return Array
     */
    public function getFiles()
    {
        return $this->_files;
    }

    /**
     * return content type
     *
     * @return string
     */
    public function getContentType()
    {
        return explode(';', $this->_server['CONTENT_TYPE'])[0];
    }

    /**
     * parse Payload
     *
     * @return array
     */
    public function parsePayload()
    {
        $contents = $this->getRawBody();
        $data = [];
        if ($contents === false) {
            return $data;
        }

        switch ($this->getContentType()) {

        case 'application/json':
            $data = (array)json_decode($contents);
            break;
        default:
            parse_str($contents, $data);
            break;
        }
        return is_array($data) ? $data : [];
    }


    /**
     * Get the form data
     *
     * @return RequestData
     */
    public function getForm()
    {
        $data = $this->parsePayload();

        foreach ($data as $key => $value) {
            $this->_post[$key] = $value;
        }

        return $this->_post;
    }

    /**
     * Get the put data
     *
     * @return RequestData
     */
    public function getPut()
    {
        if (!is_null($this->_put)) {
            return $this->_put;
        }

        $data = $this->parsePayload();

        $this->_put = new RequestData($data);

        return $this->_put;
    }

    /**
     * Get the delete data
     *
     * @return string
     */
    public function getDelete()
    {
        throw new RuntimeException('TODO');
    }

    /**
     * Get protocol of current request
     *
     * @return string
     */
    public function getProtocol()
    {
        return $this->_server['SERVER_PROTOCOL'];
    }

    /**
     * Get user agent of current request
     *
     * @return string
     */
    public function getUserAgent()
    {
        return $this->_server['HTTP_USER_AGENT'];
    }

    /**
     * 判断是否搜索引擎
     *
     * @return void
     */
    public function isRobot()
    {
        $userAgent = strtolower($this->getUserAgent());
        $bots = array(
            'bot',
            'crawl',
            'spider',
            'slurp',
            'yahoo',
            'sohu-search',
            'lycos',
            'robozilla'
        );
        foreach ($bots as $botchar) {
            if (strpos($userAgent, $botchar) !== false) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取IP地址
     *
     * @return string
     */
    public function realIp()
    {
        if (isset($this->_server['HTTP_X_FORWARDED_FOR'])) {
            $realIp = $this->_server['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($this->_server['HTTP_CLIENT_IP'])) {
            $realIp = $this->_server['HTTP_CLIENT_IP'];
        } else {
            $realIp = $this->_server['REMOTE_ADDR'];
        }
        return $realIp;
    }

    /**
     * 客户端缓存是否有效
     *
     * @param int $expires 过期时间
     *
     * @return bool
     */
    public function clientCacheIsValid($expires = self::DEFAULT_EXPIRES)
    {
        if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) === true
            && (time() - strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < $expires)
        ) {
            return true;
        }
        return false;
    }

    /**
     * Get request uri
     *
     * @return string
     */
    public function getRequestUri()
    {
        return $this->_server['REQUEST_URI'];
    }

    /**
     * Get the full URL of current request
     *
     * @return string
     */
    public function getUrl()
    {
        return $this->getHost() . $this->_server['REQUEST_URI'];
    }

    /**
     * Get the host name
     *
     * @return string
     */
    public function getHost()
    {
        return $this->getScheme() . '://' . $this->_server['HTTP_HOST'];
    }

    /**
     * Get scheme of current request
     *
     * @return string
     **/
    public function getScheme()
    {
        return isset($this->_server['SCHEME']) ? $this->_server['SCHEME'] : 'http';
    }

    /**
     * Get method of current request
     *
     * @return string
     */
    public function getMethod()
    {
        return strtoupper($this->_server['REQUEST_METHOD']);;
    }

    /**
     * If is post method
     *
     * @return Bool
     */
    public function isPost()
    {
        return ($this->getMethod() === 'POST');
    }

    /**
     * Whether an ajax request
     *
     * @return bool
     */
    public function isAjax()
    {
        return (isset($this->_server['HTTP_X_REQUESTED_WITH']) &&
            $this->_server['HTTP_X_REQUESTED_WITH'] === 'xmlhttprequest');
    }

    /**
     * get the user-defined request header
     *
     * @param string $name header name
     *
     * @return string
     */
    public function getHeader($name)
    {
        if (strtoupper(substr($name, 0, '4')) != 'HTTP') {
            $name = 'HTTP_' . $name;
        }
        $name = str_replace('-', '_', strtoupper($name));
        return isset($this->_server[$name]) ?
            $this->_server[$name] : null;
    }
}